/**
 * Project: dbcompare
 * 
 * File Created at 2010-5-27
 * $Id$
 * 
 * Copyright 2008 Alibaba.com Croporation Limited.
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of
 * Alibaba Company. ("Confidential Information").  You shall not
 * disclose such Confidential Information and shall use it only in
 * accordance with the terms of the license agreement you entered into
 * with Alibaba.com.
 */
package com.alibaba.incubator.loadtestermini.util.distribution;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Random;

/**
 * (created at 2010-5-27)
 * 
 * @author <a href="mailto:shuo.qius@alibaba-inc.com">QIU Shuo</a>
 */
public class DistributionUtils<T> {

    public DistributionUtils() {
    }

    /**
     * 归一化。以1为sum进行缩放，最后一个元素的区间是{from x, to=1}，其中，x属于[0, 1)。以便保证归一化后的区间段涵盖整个[0,
     * 1)
     * 
     * @param map MUST NOT be null; value MUST NOT be negative;
     */
    public List<IntervalItem<T>> normalize(Map<T, Double> map) {
        List<T> nodeList = new ArrayList<T>();
        List<Double> weightStartList = new ArrayList<Double>();
        double rawSum = 0;
        for (T o : map.keySet()) {
            double w = map.get(o);
            nodeList.add(o);
            weightStartList.add(rawSum);
            rawSum += w;
        }
        weightStartList.add(rawSum);
        if (rawSum <= 0) {
            throw new IllegalArgumentException("sum of weight <=0! map=" + map);
        }

        for (int i = 0; i < weightStartList.size(); ++i) {
            double num = weightStartList.get(i);
            weightStartList.set(i, num / rawSum);
        }
        weightStartList.set(weightStartList.size() - 1, 1.0d);

        List<IntervalItem<T>> rst = new ArrayList<IntervalItem<T>>();
        for (int i = 0; i < nodeList.size(); ++i) {
            T node = nodeList.get(i);
            double from = weightStartList.get(i);
            double to = weightStartList.get(i + 1);
            if (from < to) {
                rst.add(new IntervalItem<T>(from, to, node));
            }
        }
        Collections.sort(rst);
        return rst;
    }

    private static final Random random = new Random(System.currentTimeMillis());

    public T selectFromDistribution(List<IntervalItem<T>> distribution) {
        double num = random.nextDouble();
        for (IntervalItem<T> item : distribution) {
            if (item.contains(num))
                return item.getValue();
        }
        return null;
    }
}
